import platgo as pg
import numpy as np


class CF3(pg.Problem):

    def __init__(self, D: int = 10):
        self.name = "CF3"
        self.type['multi'], self.type['real'], self.type['large'], self.type['constrained'] = [True] * 4
        self.D = D
        self.M = 2
        lb = [0] + [-2] * (self.D - 1)
        ub = [1] + [2] * (self.D - 1)
        self.borders = np.array([lb, ub])
        super().__init__()

    def cal_obj(self, pop: pg.Population) -> None:
        j1 = np.arange(2, self.D, 2)
        j2 = np.arange(1, self.D, 2)
        y = pop.decs-np.sin(6*np.pi*pop.decs[:, 0].reshape(-1, 1)+np.arange(1, self.D+1) * np.pi / self.D)
        objv1 = pop.decs[:, 0] + 2 / len(j1) * (4 * np.sum(y[:, j1] ** 2, axis=1) - 2 *
                                                np.prod(np.cos(20 * y[:, j1] * np.pi / np.sqrt(j1 + 1)), axis=1)+2)
        objv2 = 1 - pop.decs[:, 0] + 2 / len(j2) * (4 * np.sum(y[:, j2] ** 2, axis=1) - 2 *
                                                    np.prod(np.cos(20*y[:, j2]*np.pi/np.sqrt(j2+1)), axis=1)+2)
        pop.objv = np.array([objv1, objv2]).T

    def cal_cv(self, pop: pg.Population) -> None:
        pop.cv = (1-pop.objv[:, 1]-pop.objv[:, 0]**2+np.sin(2*np.pi*(pop.objv[:, 0]**2-pop.objv[:, 1]+1))).reshape(-1, 1)

    def get_optimal(self) -> np.ndarray:
        raise NotImplemented("get optimal has not been implemented")
